home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Compilers⁄Interps / kevoSource / family.c < prev    next >
Text File  |  1993-05-11  |  17KB  |  493 lines

  1. /* Kevo -- a prototype-based object-oriented language */
  2. /* (c) Antero Taivalsaari 1991-1993                   */
  3. /* Some parts (c) Antero Taivalsaari 1986-1988           */
  4. /* family.c: Clone family management internals        */
  5.  
  6. #include "global.h"
  7. #include "portGlobal.h"
  8.  
  9. /*--------------------------------------------------------------------------*/
  10. /* Context management operations */
  11.  
  12. /* cloneObject(): shallow copy an existing OOP object */
  13. /* The new object is added to the clone family */
  14. /*
  15.     Note that no checks are made whether the given object really 
  16.     is a valid OOP object with its own context, so be careful.
  17. */
  18. OBJECT* cloneObject(oldObject)
  19. OBJECT* oldObject;
  20. {
  21.   /* copyObject is defined in 'memory.c' */
  22.   OBJECT*  newObject = copyObject(oldObject);
  23.   CONTEXT* context  = getContext(oldObject);
  24.  
  25.     /* Add the copy to the clone family */
  26.     addToList(context->cloneFamily, newObject);
  27.  
  28.     return(newObject);
  29. }
  30.  
  31.  
  32. /* deriveObject(): starts the addition of new properties to an existing object */
  33. /*
  34.     This operation allows objects to be derived from existing objects so that 
  35.     they both can be modified on individual basis regardless of the fact that 
  36.     sharing is used at the implementation level.        
  37.  
  38.     If the number of objects in the current clone family exceeds one, a new
  39.     clone family (child to the original one) will be created automatically,
  40.     thus guaranteeing the individual modifiability of objects, without losing
  41.     the derivation relationship between them.
  42.     
  43.     This operation should be invoked between cloning and subsequent modification.
  44.  
  45.     Note that this operation may change the context of an object, so you should
  46.     not use any old references to the context after executing this operation.
  47.     All such references must be updated using 'getContext(object)'.
  48. */
  49. void deriveObject(object)
  50. OBJECT* object;
  51. {
  52.   CONTEXT* oldContext = getContext(object);
  53.   CONTEXT* newContext;
  54.   LIST* cloneFamily = oldContext->cloneFamily;
  55.  
  56.     /* If no other copies of this object exist -> no need to create new family */
  57.     if (cloneFamily->logicalSize <= 1) return;
  58.  
  59.     /* Otherwise, build a child family:
  60.         first, duplicate the existing context (name space).
  61.     */
  62.     newContext = copyContext(oldContext);
  63.  
  64.     /* The family lists of the new context are initially empty */
  65.     newContext->cloneFamily     = createList();
  66.     newContext->parentFamilies    = createList();
  67.     newContext->childFamilies    = createList();
  68.     
  69.     /* Add the old context to the parent list of the new context */
  70.     addToList(newContext->parentFamilies, oldContext->cloneFamily);
  71.     
  72.     /* Add the new context to the child list of the old context */
  73.     addToList(oldContext->childFamilies, newContext->cloneFamily);
  74.     
  75.     /* Add the object to the new clone family */
  76.     addToList(newContext->cloneFamily, object);
  77.  
  78.     /* Remove the object from its old clone family */
  79.     /* Note that when executing this operation, the old context */
  80.     /* will not be deleted (as copy count is guaranteedly >= 2) */
  81.     removeFromItsFamily(object);
  82.     
  83.     /* Finally, replace the object's parameter field (the context) with the new context */
  84.     object->mfa->pfa = (int*)newContext;
  85. }
  86.  
  87.  
  88. /* makeParent(): make a certain object (family) a parent of another object (family) */
  89. /* If the parent is previously a child of the object, then remove it from the child */
  90. /* (only the latest 'makeParent' prevails) */
  91.  
  92. void makeParent(thisObject, parentObject)
  93. OBJECT* thisObject;
  94. OBJECT* parentObject;
  95. {
  96.   CONTEXT* thisContext = getContext(thisObject);
  97.   CONTEXT* parentContext = getContext(parentObject);
  98.  
  99.     /* If the object and suggested parent belong to the same family */
  100.     /* don't do anything */
  101.     if (thisContext == parentContext) return;
  102.  
  103.     /* If the parent is previously a child of the object, */
  104.     /* remove it from the child list */
  105.     removeFromList(thisContext->childFamilies, parentContext->cloneFamily);
  106.     removeFromList(parentContext->parentFamilies, thisContext->cloneFamily);
  107.  
  108.     /* Add the clone family of this object to the child family list */
  109.     /* of the parent object */
  110.     condAddToList(parentContext->childFamilies, thisContext->cloneFamily);
  111.     
  112.     /* Add the clone family of the parent object to the parent family */
  113.     /* list of this object */
  114.     condAddToList(thisContext->parentFamilies, parentContext->cloneFamily);
  115. }
  116.  
  117.  
  118. /* 
  119.     removeFromItsFamily(): remove the given object from its clone family,
  120.     possibly deleting the clone family and reorganizing the family hierarchy.
  121.     This operation is used internally when an object is moved to another
  122.     clone family. Be careful when using it, because after it has been executed,
  123.     the given object is hanging loose outside of any clone family.
  124. */
  125. void removeFromItsFamily(object)
  126. OBJECT* object;
  127. {
  128.   CONTEXT* context = getContext(object);
  129.   LIST* cloneFamily = context->cloneFamily;
  130.   
  131.       if (!removeFromList(cloneFamily, object)) {
  132.           fprintf(confile, "== Integrity error detected: object not found in its clone family ==\n");
  133.         reportIntegrityError();
  134.         ownLongJmp();
  135.       }
  136.       else {
  137.         /* If the family is now empty, rearrange the family hierarchy */
  138.         if (cloneFamily->logicalSize == 0) {
  139.             LIST* parf = context->parentFamilies;
  140.             LIST* chif = context->childFamilies; 
  141.             WindowPtr familyBrowser;
  142.             int index1;
  143.             int index2;
  144.  
  145.             /* Go through the parent family list */
  146.             for (index1 = 1; index1 <= parf->logicalSize; index1++) {
  147.                 OBJECT* firstObj = (OBJECT*)fetchFromList((LIST*)fetchFromList(parf, index1), 1);
  148.                 CONTEXT* firstCtxt = getContext(firstObj);
  149.                 LIST* thisList = firstCtxt->childFamilies;
  150.  
  151.                 if (thisList) {
  152.                     /* Remove the clone family from the child family lists of each parent */
  153.                     removeFromList(thisList, cloneFamily);
  154.  
  155.                     /* Add each child family to the child family list of every parent */
  156.                     for (index2 = 1; index2 <= chif->logicalSize; index2++)
  157.                         addToList(thisList, fetchFromList(chif, index2));
  158.                 }
  159.             }
  160.  
  161.               /* Go through the child family list */
  162.             for (index1 = 1; index1 <= chif->logicalSize; index1++) {
  163.                 OBJECT* firstObj = (OBJECT*)fetchFromList((LIST*)fetchFromList(chif, index1), 1);
  164.                 CONTEXT* firstCtxt = getContext(firstObj);
  165.                 LIST* thisList = firstCtxt->parentFamilies;
  166.  
  167.                 if (thisList) {
  168.                     /* Remove the clone family from the parent family lists of each child */
  169.                     removeFromList(thisList, cloneFamily);
  170.  
  171.                     /* Add each parent family to the parent family list of every child */
  172.                     for (index2 = 1; index2 <= parf->logicalSize; index2++)
  173.                         addToList(thisList, fetchFromList(parf, index2));
  174.                 }
  175.             }
  176.             
  177.             /* If there exists a browser for the clone family, delete it */
  178.             /* yyy warning: this piece of code is non-portable */
  179.             familyBrowser = findBrowser(cloneFamily);
  180.             if (familyBrowser) deleteBrowser(familyBrowser);
  181.     
  182.             /* Finally, delete the old context and its (now empty) family lists */
  183.             deleteList(context->cloneFamily);
  184.             deleteList(context->parentFamilies);
  185.             deleteList(context->childFamilies);
  186.             deleteContext(context);
  187.         }
  188.       }
  189. }
  190.  
  191.  
  192. /* moveToContext(): move the given object to another context/clone family
  193.  
  194.     Note that this operation can change the context of an object, so you should
  195.     not use any old references to the context after executing this operation.
  196.     All such references must be updated using 'getContext(object)'.
  197. */
  198. void moveToContext(object, newContext)
  199. OBJECT* object;
  200. CONTEXT* newContext;
  201. {
  202.     /* Just in case the new context happens to be the same as old */
  203.     if (getContext(object) == newContext) return;
  204.  
  205.     /* Remove the object from its old clone family, deleting the */
  206.     /* old family and possibly rearranging the family hierarchy */
  207.     removeFromItsFamily(object);
  208.     
  209.     /* Add the object to the new clone family */
  210.     addToList(newContext->cloneFamily, object);
  211.  
  212.     /* Finally, replace the object's parameter field (the context) with the new context */
  213.     object->mfa->pfa = (int*)newContext;
  214. }
  215.  
  216.  
  217. /* possiblyMoveObject(): given an object, check if there is an 
  218.     object in the given family list whose interface and operations are 
  219.     exactly the same as the given object has. If there is, move the object 
  220.     to the family of that object (removing the old family if needed).
  221.  
  222.     This operation is used for moving objects to their immediate parent
  223.     and child families when their interface changes.
  224. */
  225. int possiblyMoveObject(object, familyList)
  226. OBJECT* object;
  227. LIST* familyList;    /* List of families */
  228. {
  229.   CONTEXT* context = getContext(object);
  230.   int index;
  231.  
  232.     if (!familyList) return(FALSE);
  233.   
  234.     /* Go through all the families, looking for one with a matching interface */
  235.     for (index = 1; index <= familyList->logicalSize; index++) { 
  236.         /* Get the first object in the family */
  237.         OBJECT* firstObj = (OBJECT*)fetchFromList((LIST*)fetchFromList(familyList, index), 1);
  238.         CONTEXT* newContext = getContext(firstObj);
  239.  
  240.         /* If the parent context is similar -> move */
  241.         if (compareContexts(context, newContext)) {
  242.             moveToContext(object, newContext);
  243.             return(TRUE);
  244.         }
  245.     }
  246.     return(FALSE);
  247. }
  248.  
  249.  
  250. /* possiblyMoveFamily()
  251.     This is the same as above, but it will (possibly) move 
  252.     all the objects in the same clone family. As a result, 
  253.     the old clone family/context will be deleted.
  254. */
  255. int possiblyMoveFamily(object, familyList)
  256. OBJECT* object;
  257. LIST* familyList;
  258. {
  259.   CONTEXT* context = getContext(object);
  260.   LIST* cloneFamily = context->cloneFamily;
  261.   int count;
  262.  
  263.     count = cloneFamily->logicalSize;
  264.     
  265.     /* Try to move all the objects in the clone family */
  266.     /* Note: possiblyMoveObject slides the family list, so the index is always 1 */
  267.     while (count--) {
  268.         OBJECT* thisObject = (OBJECT*)fetchFromList(cloneFamily, 1);
  269.         if (!possiblyMoveObject(thisObject, familyList)) return(FALSE);
  270.     }          
  271.  
  272.     return(TRUE);
  273. }
  274.  
  275.  
  276. /* Move the individual object or the whole clone family upwards or downwards
  277.     in the clone family hierarchy if a suitable immediate parent or child 
  278.     family can be found. "Suitability" is based on the equivalence of 
  279.     objects' interfaces and operations.
  280.  
  281.     This operation should be invoked always after an object has undergone 
  282.     a major structural change.
  283. */
  284. void confirmObjectType(object, whoToModify, kindOfModification)
  285. OBJECT* object;
  286. int whoToModify;
  287. int kindOfModification;
  288. {
  289.   CONTEXT* context = getContext(object);
  290.   LIST* parf = context->parentFamilies;
  291.   LIST* chif = context->childFamilies;
  292.  
  293.     switch (kindOfModification) {
  294.     
  295.         case REDEFINING_SOMETHING:
  296.             /* In the current version we cannot do behavioral comparisons,
  297.                so the object or family cannot be merged with any other family 
  298.                after modifications. Sorry.
  299.             */
  300.             return;
  301.     
  302.         case REMOVING_SOMETHING: 
  303.             /* If the context is empty (has no properties) after the */
  304.             /* modifications, remove all the parents and children. */
  305.             if (context->firstPair == NIL) {
  306.                 removeAllRelatives(object);
  307.                 return;    /* This is intentionally 'return' (no need to continue) */
  308.             }
  309.     }
  310.                 
  311.     /*     In other modes, the modification may result in the object 
  312.         or family being similar to one of its parents or children
  313.         (we cannot be sure about the direction). Therefore, we try 
  314.         to rearrange the family hierarchy by trying to merge the 
  315.         object or the whole family with one of its immediate parent 
  316.         or child families 
  317.     */
  318.     switch (whoToModify) {
  319.         case THIS_ONLY:
  320.             if (possiblyMoveObject(object, parf)) break;
  321.             if (possiblyMoveObject(object, chif)) break;
  322.             break;
  323.     
  324.         case WHOLE_FAMILY:
  325.             if (possiblyMoveFamily(object, parf)) break;
  326.             if (possiblyMoveFamily(object, chif)) break;
  327.             break;
  328.             
  329.         case DERIVATIVES:
  330.             /*     When larger groups of objects are modified, 
  331.                 the hierarchy remains the same.
  332.             */
  333.             break;
  334.     
  335.     }
  336.         /*     Finally: ensure that after the modifications the object still 
  337.             has at least something in common with each of its parents. 
  338.             If it doesn't, remove parent link, but try to link the object
  339.             or family to some of the removed parent's parents.
  340.         */
  341.     ensureParentCompatibility(object);
  342. }
  343.  
  344.  
  345. /* ensureParentCompatibility(): ensure that the object has at least 
  346.     something in common with each of its parents. If it doesn't, 
  347.     remove parent link, but try to link the object's family to 
  348.     some of the removed parent's parents.
  349. */
  350. void ensureParentCompatibility(thisObject)
  351. OBJECT* thisObject;
  352. {
  353.   CONTEXT* thisContext = getContext(thisObject);
  354.   LIST* thisFamily = thisContext->cloneFamily;
  355.   LIST* parf = thisContext->parentFamilies;
  356.   int index1;
  357.  
  358.     /* Walk through each of the parents */
  359.     for (index1 = 1; index1 <= parf->logicalSize; index1++) {
  360.         /* (we utilize the fact that each clone family has at least one member) */
  361.         OBJECT* parentObject = (OBJECT*)fetchFromList((LIST*)fetchFromList(parf, index1), 1);
  362.         CONTEXT* parentContext = getContext(parentObject);
  363.  
  364.         /* Check that there is at least something in common with the 
  365.             object and the parent (i.e., at least one of the properties
  366.             must be precisely the same).
  367.         */
  368.         if (!compareContextResemblance(thisContext, parentContext)) {
  369.  
  370.             /* If there isn't any resemblance, remove the parent link */
  371.             removeFromList(thisContext->parentFamilies, parentContext->cloneFamily);
  372.             removeFromList(parentContext->childFamilies, thisContext->cloneFamily); 
  373.             
  374.             /* But, try to find some of the removed parent' parents which might match */
  375.             
  376.             /* If found, make this a parent of our object */
  377.         }
  378.     }
  379. }
  380.  
  381.  
  382. /* removeAllRelatives(): If all the properties are removed from an object 
  383.     there is not point for that object/clone family to have parents or
  384.     children any more. This operation is used to remove the parents and 
  385.     children from a given object in such a situation.
  386. */
  387. void removeAllRelatives(object)
  388. OBJECT* object;
  389. {
  390.   CONTEXT* context = getContext(object);
  391.   LIST* cloneFamily = context->cloneFamily;
  392.   LIST* parf = context->parentFamilies;
  393.   LIST* chif = context->childFamilies;
  394.   int index1;
  395.  
  396.     /* First, we remove the clone family from the child family lists of its parents */
  397.     for (index1 = 1; index1 <= parf->logicalSize; index1++) {
  398.         /* (we utilize the fact that each clone family has at least one member) */
  399.         OBJECT* firstObj = (OBJECT*)fetchFromList((LIST*)fetchFromList(parf, index1), 1);
  400.         CONTEXT* firstCtxt = getContext(firstObj);
  401.         LIST* thisList = firstCtxt->childFamilies;
  402.  
  403.         if (thisList) removeFromList(thisList, cloneFamily);
  404.     }
  405.  
  406.     /* Then, we remove the object from the parent family lists of its children */
  407.     for (index1 = 1; index1 <= chif->logicalSize; index1++) {
  408.         OBJECT* firstObj = (OBJECT*)fetchFromList((LIST*)fetchFromList(chif, index1), 1);
  409.         CONTEXT* firstCtxt = getContext(firstObj);
  410.         LIST* thisList = firstCtxt->parentFamilies;
  411.  
  412.         if (thisList) removeFromList(thisList, cloneFamily);
  413.     }
  414.  
  415.     /* Finally, we can now empty the parent and child families of the object */
  416.     emptyList(parf);
  417.     emptyList(chif);
  418. }
  419.  
  420.  
  421. /* resizeFamilyMembers(): given an object, resize all the objects in its clone family */
  422. /* This operation is needed when VARs are added to an object */
  423.  
  424. void resizeFamilyMembers(object, newSize)
  425. OBJECT* object;
  426. int newSize;
  427. {
  428.   CONTEXT* context = getContext(object);
  429.   LIST* cloneFamily = context->cloneFamily;
  430.   int familySize = cloneFamily->logicalSize;
  431.  
  432.     if (familySize > 0) {
  433.         int index;
  434.  
  435.         /* Resize each member of the clone family */    
  436.         for (index = 1; index <= familySize; index++) {
  437.             OBJECT* member = (OBJECT*)fetchFromList(cloneFamily, index);
  438.             resizeClosure(member, newSize);
  439.         }
  440.     }
  441.     /* 
  442.         In the current implementation, it is possible that some objects 
  443.         have an empty clone family. For such objects, do the plain resize.
  444.     */
  445.     else resizeClosure(object, newSize);
  446. }
  447.  
  448.  
  449. /* CheckFamilyIntegrity(): check the integrity of a clone family 
  450.    by ensuring that the current clone family is found in the child family 
  451.    lists of its parents, and in the parent family lists of its children.
  452.    Return TRUE if the family is ok, FALSE otherwise.
  453.  
  454.    This operation is used solely for ensuring that the other family 
  455.    operations work correctly.
  456. */
  457. int checkFamilyIntegrity(context)
  458. CONTEXT* context;
  459. {
  460.   LIST* cf = context->cloneFamily;
  461.   LIST* parf = context->parentFamilies;
  462.   LIST* chif = context->childFamilies;
  463.   int index;
  464.  
  465.     /* Go through the parent family list */
  466.     for (index = 1; index <= parf->logicalSize; index++) {
  467.         OBJECT* firstObj = (OBJECT*)fetchFromList((LIST*)fetchFromList(parf, index), 1);
  468.         CONTEXT* firstCtxt = getContext(firstObj);
  469.         LIST* thisList = firstCtxt->childFamilies;
  470.  
  471.         if (!findInList(thisList, cf)) {
  472.             fprintf(confile, "== Integrity error detected: family not found in the child list of its parent ==\n");
  473.             return(FALSE);
  474.         }        
  475.     }
  476.  
  477.     /* Go through the child family list */
  478.     for (index = 1; index <= chif->logicalSize; index++) {
  479.         OBJECT* firstObj = (OBJECT*)fetchFromList((LIST*)fetchFromList(chif, index), 1);
  480.         CONTEXT* firstCtxt = getContext(firstObj);
  481.         LIST* thisList = firstCtxt->childFamilies;
  482.  
  483.         if (!findInList(thisList, cf)) {
  484.             fprintf(confile, "== Integrity error detected: family not found in the parent list of its child ==\n");
  485.             return(FALSE);
  486.         }
  487.     }
  488.  
  489.     return(TRUE);
  490. }
  491.  
  492.  
  493.